﻿using NovoSerDes.Funcs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace NovoSerDes.Forms
{
    public partial class Form_EOM : Form
    {
        SerDesComm commDev;
        public Form_EOM(SerDesComm commDev)
        {
            InitializeComponent();
            this.commDev = commDev;

            this.cmb_ChannelSel.SelectedIndex = 0;
            this.cmb_popThresh.SelectedIndex = 4;
            this.cmb_UICode.SelectedIndex = 2;
        }

        #region Params
        SerDesCH cur_ch = SerDesCH.CH_A;
        int ui_align_tgt_phase = 0;
        int ui_align_last_phase = 0;

        UInt32 eom_ui_align_fail = 0;
        //UInt32 if_eom_ui_align_fail = 0;

        UInt32 DFE_F0 = 0;
        int UI_CODE = 64;   //12.8/8/6.4Gbps ->64; 4/6.4Gbps -> 256; 2Gbps -> 256
        int[][] eye_diagram = new int[128][];         // storage eye’s Horizontal and vertical coordinates
        long esm_pop_thresh = 10 ^ 4;

        int eye_pass_p_n = 0;
        int eye_pass_n = 0;
        #endregion


        #region Funcs
        private bool Update_UI_Code()
        {
            UI_CODE = 64;   //ToDo: change based on speed, need read back speed registers
            return false;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ns_ew">True: ew; False: ns</param>
        /// <returns></returns>
        private bool EOM_Init(SerDesCH ch)
        {
            bool ret = true;
            int offset = 0;
            int timeout = 1000;     // 1000*5ms = 5Sec

            // 3.1 - 3.2: NS_Base + 0x1000 = EW_Base
            offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            #region (1) Set EOM Registers
            //ret = commDev.IICWrite((UInt32)(0x7464 + offset), 0x01, 12, 12);   //reg_dc_os_update_en_normal = 1
            ret &= commDev.IICWrite((UInt32)(0x7484 + offset), 0x01, 17, 21);  //reg_eom_ui_align_pos = 1	
            ret &= commDev.IICWrite((UInt32)(0x74F0 + offset), 0x01, 30, 30);  //reg_skip_norm_eom_f1_align = 1
            ret &= commDev.IICWrite((UInt32)(0x74F0 + offset), 0x01, 29, 29);  //reg_skip_norm_ph_align = 1
                                                                               // Set esm_pop_thres
            UInt32 tempData = (UInt32)esm_pop_thresh;
            ret &= commDev.IICWrite((UInt32)(0x752C + offset), tempData, 0, 31);  //reg_eom_set1_pop_cnt1 for low 32bits
            tempData = (UInt32)(esm_pop_thresh >> 32);
            ret &= commDev.IICWrite((UInt32)(0x7530 + offset), tempData, 0, 31);  //reg_eom_set1_pop_cnt1 for high 32bits

            ret &= commDev.IICWrite((UInt32)(0x7464 + offset), 0x05, 16, 18);     //Set EOM UI Align err_cnt 's max value is 32
            if (!ret)
                return ret;
            #endregion 


            #region (2) Set Other Registers and global variables
            ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x0, 24, 24);    //dfe_update_en_bc = 0
            ui_align_tgt_phase = 0;
            ui_align_last_phase = 0;
            if (!ret)
                return ret;
            #endregion

            // 3 - 7 from top register group; EW_Base + 0x70 = BS_Base
            offset = (ch < SerDesCH.CH_NS) ? 0x70 : 0;

            #region (3) Enable SERDES
            ret = commDev.IICWrite((UInt32)(0x64 + offset), 0x1, 12, 12);        //PIN_PU_PLL0 = 1
            ret &= commDev.IICWrite((UInt32)(0x64 + offset), 0x1, 10, 10);       //PIN_PU_TX0 = 1
            ret &= commDev.IICWrite((UInt32)(0x64 + offset), 0x1, 11, 11);       //PIN_PU_RX0 = 1  
            if (!ret)
                return ret;
            #endregion

            #region (4) Wait PLL Ready
            UInt32 Pin_PLL_Ready_TRX0 = 0;
            //Wait PIN_PLL_READY_TX0 = 1 && Wait PIN_PLL_READY_RX0 = 1
            timeout = 1000;          // 1000*5ms = 5Sec
            do
            {
                ret = commDev.IICRead((UInt32)(0x34 + offset), out Pin_PLL_Ready_TRX0, 11, 12);  //Wait PLL Ready
                if (!ret)
                    return ret;

                Thread.Sleep(5);

            }
            while((Pin_PLL_Ready_TRX0 != 0x03) && (--timeout > 0));

            if (timeout == 0)
                return false;            
            #endregion

            #region (5) - DFE Power On
            ret = commDev.IICWrite((UInt32)(0x64 + offset), 0x1, 23, 23);        //PIN_DFE_EN0 = 1
            ret &= commDev.IICWrite((UInt32)(0x64 + offset), 0x1, 22, 23);        //PIN_DFE_PAT_DIS0 = 1
            ret &= commDev.IICWrite((UInt32)(0x64 + offset), 0x0, 21, 21);        //PIN_DFE_UPDATE_DIS0 = 0  
            if (!ret)
                return ret;
            #endregion

            #region (6) - RX Init
            ret = commDev.IICWrite((UInt32)(0x74 + offset), 0x1, 28, 28);        //PIN_RX_INIT0 = 1
            ret &= commDev.IICWrite((UInt32)(0x40 + offset), 0x1, 9, 9);          //Wait PIN_RX_INIT_DONE0 = 1
            ret &= commDev.IICWrite((UInt32)(0x74 + offset), 0x0, 28, 28);        //PIN_RX_INIT0 = 0
            if (!ret)
                return ret;
            #endregion


            #region (7) - RX Trainning
            ret = commDev.IICWrite((UInt32)(0x74 + offset), 0x1, 27, 27);        //PIN_RX_TRAIN_ENABLE0 = 1
            ret &= commDev.IICWrite((UInt32)(0x40 + offset), 0x1, 8, 8);          //Wait PIN_RX_TRAIN_COMPLETE0 = 1
            if (!ret)
                return ret;
            #endregion

            // 3.8 - 3.10: NS_Base + 0x1000 = EW_Base
            offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;
            #region (8) - Save F0
            ret = commDev.IICRead((UInt32)(0x741C + offset), out DFE_F0, 17, 22);  //Read reg_rd_dfe_f0[5:0]
            if (!ret)
                return ret;
            #endregion

            #region (9) - Enable Eye Monitor
            Thread.Sleep(1);        // delay 10000ns, actually delayed 1ms
            ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x1, 10, 10);        //reg_eom_en = 1            
            UInt32 eom_ready = 0;
            timeout = 1000;          // 1000*5ms = 5Sec
            while (--timeout > 0)
            {
                ret &= commDev.IICRead((UInt32)(0x7418 + offset), out eom_ready, 31, 31);  //Read reg_rd_dfe_f0[5:0])
                if (!ret)
                    return ret;
                else if (eom_ready == 1)
                    break;

                Thread.Sleep(5);
            }
            if (timeout == 0)
                return false;
            #endregion

            #region (10) - set esm voltage
            int ems_vol = 0; //ToDo, verify voltage value
            ret = EOM_Set_ESM_Voltage(ems_vol, ch);
           #endregion

            return ret;
        }

        private bool EOM_Alignment(SerDesCH ch)
        {
            bool ret = false;

            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            #region (11) Execute EOM Align Calibration
            ret = commDev.IICWrite((UInt32)(0x7590 + offset), 0x1, 4, 4);        //reg_align_eom_start = 1
            ret &= commDev.IICWrite((UInt32)(0x7590 + offset), 0x0, 4, 4);       //reg_align_eom_start = 0
            //ret &= commDev.IICWrite((UInt32)(0x7574 + offset), 0x1, 2, 2);       //reg_rd_align_eom_done = 1
            if (!ret)
                return ret;

            // wait reg_rd_align_eom_done = 1
            UInt32 align_eom_done = 0;
            int timeout = 1000;     //1000*5ms = 5Sec
            do
            { 
                ret = commDev.IICRead((UInt32)(0x7574 + offset), out align_eom_done, 2, 2);
                if(!ret)
                    return ret;

                Thread.Sleep(5);
            } while ((--timeout > 0) && (align_eom_done == 0));

            if(align_eom_done == 0)
                return false;
            #endregion

            #region (12) Clear DFE Done ISR
            ret = commDev.IICWrite((UInt32)(0x7464 + offset), 0x1, 2, 2);        //reg_dfe_done_int_clear = 1
            ret &= commDev.IICWrite((UInt32)(0x7464 + offset), 0x0, 2, 2);        //reg_dfe_done_int_clear = 0
            if (!ret)
                return ret;
            #endregion

            #region (13) Loop execute eom_ui_align
            int maxLoopTimes = 20;
            for (int ix = 0; ix < maxLoopTimes; ix++)
            {
                int ui_align_ret = EOM_UI_Align(ch);
                if (ui_align_ret == -1)
                    return false;
                else if (ui_align_ret == 0)
                    break;
            }

            ret = commDev.IICRead((UInt32)(0x7420 + offset), out eom_ui_align_fail, 2, 2);  //Read reg_rd_eom_ui_align_fail;  
            if (!ret)
                return ret;

            if (eom_ui_align_fail == 0)
                return false;
            #endregion

            return ret;
        }
        
        private int EOM_UI_Align(SerDesCH ch)
        {
            bool ret = false;
            
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            #region //(1) Read Calibration Results and 
            UInt32 cal_eom_ph = 0;
            ret = commDev.IICRead((UInt32)(0x7574 + offset), out cal_eom_ph, 4, 10);  //Read reg_rd_dfe_f0[5:0]
            if (!ret)
                return -1;
            #endregion

            #region //(2) EOM UI Align Start
            ret = commDev.IICWrite((UInt32)(0x7484 + offset), 0x01, 16, 16);  //reg_eom_ui_align_start_bits = 1
            ret &= commDev.IICWrite((UInt32)(0x7484 + offset), 0x0, 16, 16);  //reg_eom_ui_align_start_bits = 0
            if (!ret)
                return -1;
            #endregion

            #region //(3) Read dfe_done_int
            UInt32 if_dfe_done = 0;
            int timeout = 1000; // 1000*5ms = 5Sec
            do
            {
                ret = commDev.IICRead((UInt32)(0x741C + offset), out if_dfe_done, 23, 23);  //Read reg_rd_dfe_done_int
                if (!ret)
                    return -1;

                Thread.Sleep(5);
            }
            while ((if_dfe_done == 0) && (--timeout > 0));

            Console.WriteLine("dfe wait done timeout:{0}", timeout);
            if (timeout == 0)
                return -1;
            #endregion

            #region // (4) Clear dfe_done ISR
            ret = commDev.IICWrite((UInt32)(0x7464 + offset), 0x01, 2, 2);  //reg_dfe_done_int_clear = 1
            ret &= commDev.IICWrite((UInt32)(0x7464 + offset), 0x0, 2, 2);  //reg_dfe_done_int_clear = 0
            if (!ret)
                return -1;            
            #endregion

            #region (5) Wait utill eom ui align done
            UInt32 if_eom_ui_align_done = 0;
            timeout = 1000; // 1000*5ms = 5Sec
            do
            {
                ret = commDev.IICRead((UInt32)(0x7420 + offset), out if_eom_ui_align_done, 3, 3);  //Read reg_rd_eom_ui_align_done
                if (!ret)
                    return -1;

                Thread.Sleep(5);
            }
            while ((if_eom_ui_align_done == 0) && (--timeout > 0));
            Console.WriteLine("wait eom_ui_align_done timeout:{0}", timeout);
            if(timeout == 0) return -1;
            
            ret = commDev.IICRead((UInt32)(0x7420 + offset), out eom_ui_align_fail, 2, 2);  //Read reg_rd_eom_ui_align_fail
            if (!ret)
                return -1;
            #endregion

            #region (6) Loop execute eom_ui_align_set_phase(pi)
            int step_ui_algh = 2;
            if (eom_ui_align_fail == 1)
            {
                for (int pi = 0; pi < UI_CODE; pi += step_ui_algh)
                {
                    ui_align_tgt_phase = pi + ui_align_last_phase;
                    if (EOM_UI_Align_Set_Phase(ui_align_tgt_phase % 128, ch) == false)
                        return -1;
                }
                ui_align_last_phase = ui_align_tgt_phase;
                return 1;
            }
            else
            {
                Console.WriteLine("UI Align Success!");
                ui_align_last_phase = ui_align_tgt_phase;
                return 0;
                //indey = 20;  //Break for loop		//ToDo 如何操作？？
            }
            #endregion
        }
          
        int esm_phase = 0;
        int esm_voltage = 0;
        int cur_phase = 0;
        int eye_vp = 64;              //Top side maxvoltage initial value
        int eye_vn = 64;              //Bottom side minvoltage initial value
        int esm_v_step = 1;           // esm voltagesweep step size
        int esm_p_step = 1;           // esm phase sweepstep size
        int eye_hc = 64;
        int eye_vc = 64;
        int eye_hl = 0;
        int eye_hr = 0;
        private bool EOM_Print(SerDesCH ch)
        {
            bool ret = false;
            int timeout = 1000;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            #region EOM Sweep Initialization
            //int esm_phase = 0;
            //int esm_voltage = 0;
            //int eye_vp = 64;              //Top side maxvoltage initial value
            //int eye_vn = 64;              //Bottom side minvoltage initial value
            //int esm_v_step = 1;           // esm voltagesweep step size
            //int esm_p_step = 1;           // esm phase sweepstep size
            //int eye_hc = 64;
            //int eye_vc = 64;
            //int eye_hl = 0;
            //int eye_hr = 0;
            
            for(int ix = 0; ix < 128; ix++)
                eye_diagram[ix] = new int[128];
            #endregion 

            #region (15) Count Rising Edge (Upper Half Eye)
            ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x1, 30, 31);        //reg_pattern = 2’b01
            if (!ret)
                return ret;
            #endregion 

            #region (16) DFE F0 Polarity 
            ret = commDev.IICWrite((UInt32)(0x753C + offset), 0x1, 17, 18);       //reg_eom_set1_eom_state = 2’b01
            if (!ret)
                return ret;
            #endregion 

            #region (17) Read Calibration Results And Save
            UInt32 cal_eom_ph = 0;
            ret = commDev.IICRead((UInt32)(0x7574 + offset), out cal_eom_ph, 4, 10);  //Read reg_rd_cal_eom_ph_rd_bits[6:0]	
            if (!ret)
                return ret;

            //Set global variable: cur_phase
            cur_phase = ui_align_tgt_phase % 128;

            ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x0, 25, 30);          //Turn Off dfe_update_en
            if (!ret)
                return ret;
            #endregion

            #region (18) set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;

            #endregion

            #region (19) Sweep Phase from center to right and Voltage from center to top
            ret = EOM_Sweep_Phase(false, true, ch);
            if (!ret)
                return false;
            //for (esm_phase = 0; esm_phase < 61; esm_phase += esm_p_step)
            //{
            //    if(!EOM_Set_ESM_Phase(esm_phase, ch))
            //        return false; 

            //    for (esm_voltage = 0; esm_voltage < 61; esm_voltage += esm_v_step)
            //    {
            //        if(!EOM_Set_ESM_Voltage(esm_voltage, ch))
            //            return false;

            //        ret = EOM_Check_Eye(esm_phase, esm_voltage, true, ch);
            //        if (!ret)
            //            return ret;

            //        if ((eye_vp < (eye_vc + esm_voltage)) && (eye_pass_p_n == 1))
            //            eye_vp = eye_vc + esm_voltage;
            //        if ((eye_vn > (eye_vc - esm_voltage)) && (eye_pass_n == 1))
            //            eye_vn = eye_vc - esm_voltage;
            //        if ((eye_pass_p_n == 0) && (eye_pass_n == 0))
            //            break;
            //    }
            //}

            #endregion

            #region (20) set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion

            #region (21) Sweep Phase from center to left and Voltage from center to top
            ret = EOM_Sweep_Phase(true, true, ch);
            if (!ret)
                return false;
            #endregion 

            #region (22) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion 

            #region (23) Find Boundary
            while (eye_vp < 127)
            {
                eye_vp++;
            }
            while (eye_vn > 0)
            {
                eye_vn--;
            }

            #endregion 


            #region (24) Execute plot_eye
            #endregion 

            #region (25) EOM Sweep Initialization
            esm_phase = 0;
            esm_voltage = 0;
            eye_vp = 64;
            eye_vn = 64;

            #endregion 

            #region (26) Count Rising Edge (Upper Half Eye)
            ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x2, 30, 31);       //reg_pattern = 2 'b10
            if (!ret)
                return ret;
            #endregion 

            #region (27) DFE F0 Polarity
            ret = commDev.IICWrite((UInt32)(0x753C + offset), 0x0, 17, 18);       //reg_eom_set1_eom_state = 2 'b00
            if (!ret)
                return ret;
            #endregion 

            #region (28) Read Calibration Results And Save
            cal_eom_ph = 0;
            ret = commDev.IICRead((UInt32)(0x7574 + offset), out cal_eom_ph, 4, 10);  //Read reg_rd_cal_eom_ph_rd_bits[6:0]	
            if (!ret)
                return ret;

            //Set global variable: cur_phase
            cur_phase = ui_align_tgt_phase % 128;

            //ret = commDev.IICWrite((UInt32)(0x7480 + offset), 0x0, 25, 30);          //Turn Off dfe_update_en
            //if (!ret)
            //    return ret;
            #endregion 

            #region (29) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion 

            #region (30) Sweep Phase from center to right and Voltage from center to bottom
            ret = EOM_Sweep_Phase(false, false, ch);
            if (!ret)
                return false;
            #endregion 

            #region (31) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion

            #region (32) Sweep Phase from center to left and Voltage from center to bottom
            ret = EOM_Sweep_Phase(true, false, ch);
            if (!ret)
                return false;
            #endregion

            #region (33) Execute set_esm_phase(0)
            if (!EOM_Set_ESM_Phase(0, ch))
                return false;
            #endregion

            #region (34) Find Boundary
            while (eye_vp < 127)
            {
                eye_vp++;
            }
            while (eye_vn > 0)
            {
                eye_vn--;
            }

            #endregion

            #region (35) Execute plot_eye
            #endregion

            #region 3.5 Turn Off EOMc
            ret = commDev.IICWrite((UInt32)(0x7420 + offset), 0x0, 11, 11);       //reg_eom_en = 0;
            if (!ret)
                return ret;

            UInt32 eom_ready = 0;
            timeout = 1000;          // 1000*5ms = 5Sec
            while (--timeout > 0)
            {
                ret &= commDev.IICRead((UInt32)(0x7418 + offset), out eom_ready, 31, 31);  //Read reg_rd_dfe_f0[5:0])
                if (!ret)
                    return ret;
                else if (eom_ready == 0)
                    break;

                Thread.Sleep(5);
            }
            if (timeout == 0)
                return false;
            #endregion 

            return ret;
        }

        private bool EOM_Set_ESM_Voltage(int voltage, SerDesCH ch)
        {
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;
            bool ret = false;

            if (voltage >= Math.Pow(2, 6))
                return false;

            ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)voltage, 26, 31); //reg_eom_set1_voltage_bits = v[5:0]
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 1, 29, 29);             //reg_eom_set1_v ld_bits = 1
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 1, 27, 28);             //reg_eom_set1_stop_en_bits = 2 'b01 
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0, 29, 29);             //reg_eom_set1_v ld_bits = 0
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0, 27, 28);             //reg_eom_set1_stop_en_bits = 2 'b00

            return ret;
        }

        private bool EOM_UI_Align_Set_Phase(int pi, SerDesCH ch)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)pi, 19, 25);  //reg_eom_set1_phase = pi
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 29, 29);       //reg_eom_set1_vld = 1
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 27, 28);       //reg_eom_set1_stop_en = 2’b01	
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x0, 29, 29);       //reg_eom_set1_vld = 0
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x0, 27, 28);       //reg_eom_set1_stop_en = 2’b00

            return ret;
        }

        private bool EOM_Set_ESM_Phase(int phase, SerDesCH ch)
        {
            bool ret = true;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            int cur_phase = 0;
            int target_phase = 0;
            int step = 1;
            target_phase = (ui_align_tgt_phase % 128) + phase;
            if (cur_phase <= target_phase)
            {
                while ((target_phase - cur_phase) >= step)
                {
                    cur_phase += step;
                    if (!EOM_Set_EOM_Phase(cur_phase, ch))
                        return false;
                }
            }
            else
            {
                while ((cur_phase - target_phase) > step)
                {
                    cur_phase -= step;
                    if (!EOM_Set_EOM_Phase(cur_phase, ch))
                        return false;
                }
                cur_phase = target_phase;
                if (!EOM_Set_EOM_Phase(cur_phase, ch))
                    return false;
            }

            return ret;
        }

        private bool EOM_Check_Eye(int phase, int voltage, bool if_top, SerDesCH ch)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            long pop_p_n;
            long err_p_n;
            float ber_p_n;
            int x, y;

            pop_p_n = 0;
            err_p_n = 0;

            ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x1, 29, 29);       //reg_eom_set1_vld = 1
            if (!ret)
                return ret;

            Thread.Sleep(1);        //delay 200ns; wait EOM state machine enter SET1 state

            do
            {
                UInt32 tempData = 0;
                ret = commDev.IICRead((UInt32)(0x768C + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[31:0];	
                pop_p_n = (long)tempData;
                ret &= commDev.IICRead((UInt32)(0x7690 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[63:32];
                pop_p_n += tempData << 32;
                if (!ret)
                    return ret;

                ret = commDev.IICRead((UInt32)(0x7680 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_error_cnt[31:0];	
                err_p_n = (long)tempData;
                ret &= commDev.IICRead((UInt32)(0x7684 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_error_cnt[63:32];
                err_p_n += tempData << 32;
                if (!ret)
                    return ret;

                //pop_p_n = reg_rd_eom_set1_sample_cnt[63:0];
                //err_p_n = reg_rd_eom_set1_error_cnt[63:0];
            } while (pop_p_n < esm_pop_thresh);

            if (pop_p_n == 0)
                return false;

            ber_p_n = err_p_n / pop_p_n;

            x = 64 + phase;
            y = if_top ? 64 + voltage : 64 - voltage;

            if (err_p_n >= 1) eye_diagram[x][y] = 1;
            else eye_diagram[x][y] = 0;

            if (err_p_n < 1) eye_pass_p_n = 1;
            else eye_pass_p_n = 0;

            do
            {
                UInt32 tempData = 0;
                ret = commDev.IICRead((UInt32)(0x768C + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[31:0];	
                pop_p_n = (long)tempData;
                ret &= commDev.IICRead((UInt32)(0x7690 + offset), out tempData, 0, 31);  //reg_rd_eom_set1_sample_cnt[63:32];
                pop_p_n += tempData << 32;
                if (!ret)
                    return ret;
                Thread.Sleep(1);
            } while (pop_p_n < esm_pop_thresh);

            UInt32 eom_set1_rdy = 0;
            ret = commDev.IICRead((UInt32)(0x7688 + offset), out eom_set1_rdy, 31, 31);      //Read reg_rd_eom_set1_rdy;
            if (!ret)
                return false;

            if(eom_set1_rdy == 1)
                ret = commDev.IICWrite((UInt32)(0x7528 + offset), 0x0, 29, 29);             //reg_eom_set1_vld = 0;

            return ret;
        }

        private bool EOM_Sweep_Phase(bool if_left, bool if_top, SerDesCH ch)
        {
            bool ret = true;

            if (if_left)    // Center to left
            {
                for (esm_phase = 0; esm_phase > -36; esm_phase -= esm_p_step)
                {
                    ret = EOM_Set_ESM_Phase(esm_phase, ch);
                    if (!ret)
                        return false;

                    for (esm_voltage = 0; esm_voltage < 61; esm_voltage += esm_v_step)
                    {
                        if (!EOM_Set_ESM_Phase(esm_voltage, ch))
                            return false;
                        if (!EOM_Check_Eye(esm_phase, esm_voltage, if_top, ch))
                            return false;

                        if ((eye_vp < (eye_vc + esm_voltage)) && (eye_pass_p_n == 1))
                            eye_vp = if_top ? eye_vc + esm_voltage : eye_vc - esm_voltage;

                        //eye_vp = eye_vc + esm_voltage;
                        //if ((eye_vn > (eye_vc - esm_voltage)) && (eye_pass_p_n == 1))
                        //    eye_vn = eye_vc - esm_voltage;

                        if (eye_pass_p_n == 0)
                            break;
                    }
                    if (esm_voltage == 0)   //ToDo: 这条命令执行不到
                    {
                        eye_hl = eye_hc + esm_phase;
                        break;
                    }
                }
            }
            else       // Center to right
            {                
                for (esm_phase = 0; esm_phase < 36; esm_phase += esm_p_step)
                {
                    ret = EOM_Set_ESM_Phase(esm_phase, ch);
                    if (!ret)
                        return false;

                    for (esm_voltage = 0; esm_voltage < 61; esm_voltage += esm_v_step)
                    {
                        if (!EOM_Set_ESM_Phase(esm_voltage, ch))
                            return false;
                        if (!EOM_Check_Eye(esm_phase, esm_voltage, if_top, ch))
                            return false;

                        if ((eye_vp < (eye_vc + esm_voltage)) && (eye_pass_p_n == 1))
                            eye_vp = if_top ? eye_vc + esm_voltage : eye_vc - esm_voltage;
                        //if ((eye_vn > (eye_vc - esm_voltage)) && (eye_pass_n == 1))
                        //    eye_vn = eye_vc - esm_voltage;
                        if (eye_pass_p_n == 0)
                            break;
                    }
                }
            }


            return ret;
        }

        private bool EOM_Set_EOM_Phase(int phase, SerDesCH ch)
        {
            bool ret = false;
            // NS_Base + 0x1000 == EW_Base
            int offset = (ch < SerDesCH.CH_NS) ? 0 : 0x1000;

            if (phase >= Math.Pow(2, 7))
                return false;

            Console.WriteLine("Set phase:{0}", phase);

            ret = commDev.IICWrite((UInt32)(0x753C + offset), (UInt32)phase, 19, 25);  //reg_eom_set1_phase[6:0] = cur_phase[6:0]
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 29, 29);          //reg_eom_set1_v ld = 1
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x01, 27, 28);          //reg_eom_set1_stop_en = 2’b01	
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x00, 29, 29);          //reg_eom_set1_v ld = 0
            ret &= commDev.IICWrite((UInt32)(0x7528 + offset), 0x00, 27, 28);          //reg_eom_set1_stop_en = 2’b00
            if (!ret)
                return ret;

            return ret;
        }

        private void EOM_Plot_Eye()
        {
            int x;
            int y;

            Console.WriteLine("*****************************************\n");
            Console.WriteLine("************EYE DIAGRAM BEGIN************\n");
            Console.WriteLine("*****************************************\n");

            for (y = eye_vp; y >= eye_vn; y--)
            {
                Console.WriteLine("<%3d>", y);
                if (y == 0)
                {
                    Console.WriteLine(" ");
                    break;
                }
                for (x = 29; x <= 99; x++)
                {
                    if (eye_diagram[x][y] == 1) Console.WriteLine(" ");
                    else Console.WriteLine("%b", eye_diagram[x][y]);
                } // x
                Console.WriteLine(" ");
            } // y

            Console.WriteLine("*****************************************\n");
            Console.WriteLine("************EYE DIAGRAM END**************\n");
            Console.WriteLine("*****************************************\n");

        }


        #endregion Funcs


        enum SerDesCH
        {
            CH_A = 0,
            CH_B = 1,
            CH_NS = 2,
            CH_C = 10,
            CH_D = 11,
            CH_EW = 12
        }

        private void cmb_ChannelSel_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch(cmb_ChannelSel.SelectedIndex)
            {
                case 0:
                    cur_ch = SerDesCH.CH_A;
                    break;
                case 1:
                    cur_ch = SerDesCH.CH_B;
                    break; 
                case 2:
                    cur_ch = SerDesCH.CH_C;
                    break;
                case 3:
                    cur_ch = SerDesCH.CH_D;
                    break;
            }
        }

        private void cmb_popThresh_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.esm_pop_thresh = (long)Math.Pow(10, this.cmb_popThresh.SelectedIndex + 1);
        }
        
        private void cmb_UICode_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.UI_CODE =(int)(64 * Math.Pow(2, this.cmb_UICode.SelectedIndex));
        }

        private void btn_StartEOM_Click(object sender, EventArgs e)
        {
            bool ret = false;
            ret = EOM_Init(cur_ch);
            if (!ret)
            {
                Console.WriteLine("EOM Init Fialed!");
                return;
            }
            else
                Console.WriteLine("EOM Init Done");

            ret = EOM_Alignment(cur_ch);
            if (!ret)
            {
                Console.WriteLine("EOM_Alignment Fialed!");
                return;
            }

            ret = EOM_Print(cur_ch);
            if (!ret)
            {
                Console.WriteLine("EOM_Print Fialed!");
                return;
            }
            
        }

       
    }
}
